package com.ssy.lingxi.report.serviceimpl;

import cn.hutool.core.date.DateUtil;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.report.api.enums.CommodityOperateTypeEnum;
import com.ssy.lingxi.report.api.enums.MemberOperateTypeEnum;
import com.ssy.lingxi.report.api.enums.OperateDataSourceEnum;
import com.ssy.lingxi.report.api.enums.ShopOperateTypeEnum;
import com.ssy.lingxi.report.api.vo.request.AddOrderVO;
import com.ssy.lingxi.report.api.vo.request.OperateNoticeVO;
import com.ssy.lingxi.report.dao.merchantmember.MemberDAO;
import com.ssy.lingxi.report.dao.platformtemplate.MemberShopDAO;
import com.ssy.lingxi.report.dao.product.BrandDAO;
import com.ssy.lingxi.report.dao.product.CommodityDAO;
import com.ssy.lingxi.report.dao.report.OrderAddRecordDAO;
import com.ssy.lingxi.report.entity.report.NewlyAddedDayReportDO;
import com.ssy.lingxi.report.model.bo.StatisticsNewlyAddedBO;
import com.ssy.lingxi.report.model.bo.StatisticsOrderNewlyAddedBO;
import com.ssy.lingxi.report.model.vo.response.NewlyAddedDayReportVO;
import com.ssy.lingxi.report.repository.report.NewlyAddedDayReportRepository;
import com.ssy.lingxi.report.service.INewlyAddedDayReportService;
import com.ssy.lingxi.report.utils.TimeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class NewlyAddedDayReportServiceImpl implements INewlyAddedDayReportService {

    private static final Logger logger = LoggerFactory.getLogger(NewlyAddedDayReportServiceImpl.class);

    @Resource
    private NewlyAddedDayReportRepository reportRepository;

    @Resource
    private MemberDAO memberDAO;

    @Resource
    private MemberShopDAO memberShopDAO;

    @Resource
    private CommodityDAO commodityDAO;

    @Resource
    private BrandDAO brandDAO;

    @Resource
    private OrderAddRecordDAO orderAddRecordDAO;

    /**
     * 新增日报表
     * @author 伍将
     * @date 2020/11/12
     * @param startTime:
     * @param endTime:
     **/
    @Transactional
    @Override
    public void newlyAddedDayReport(LocalDateTime startTime, LocalDateTime endTime) {

        // 查询新增会员
        List<StatisticsNewlyAddedBO> memberNewlyAddedBOS = memberDAO.getNewlyAddedMemberByDay(startTime, endTime);
        logger.info("统计日新增会员：{}", memberNewlyAddedBOS != null ? memberNewlyAddedBOS.size() : 0);

        // 查询新增订单
        List<StatisticsOrderNewlyAddedBO> orderNewlyAddedBOS = orderAddRecordDAO.getNewlyAddedOrderByDay(startTime, endTime);
        logger.info("统计日新增订单：{}", orderNewlyAddedBOS != null ? orderNewlyAddedBOS.size() : 0);

        // 查询新增店铺
        List<StatisticsNewlyAddedBO> shopNewlyAddedBOS = memberShopDAO.getNewlyAddedShopByDay(TimeUtil.getTimestampOfDateTime(startTime), TimeUtil.getTimestampOfDateTime(endTime));
        logger.info("统计日新增店铺：{}", shopNewlyAddedBOS != null ? shopNewlyAddedBOS.size() : 0);

        // 查询新增商品
        List<StatisticsNewlyAddedBO> commodityNewlyAddedBOS = commodityDAO.getNewlyAddedCommodityByDay(TimeUtil.getTimestampOfDateTime(startTime), TimeUtil.getTimestampOfDateTime(endTime));
        logger.info("统计日新增商品：{}", commodityNewlyAddedBOS != null ? commodityNewlyAddedBOS.size() : 0);

        // 查询新增品牌
        List<StatisticsNewlyAddedBO> brandNewlyAddedBOS = brandDAO.getNewlyAddedBrandByDay(TimeUtil.getTimestampOfDateTime(startTime), TimeUtil.getTimestampOfDateTime(endTime));
        logger.info("统计日新增品牌：{}", brandNewlyAddedBOS != null ? brandNewlyAddedBOS.size() : 0);

        String startDate = TimeUtil.getDateTimeAsString(startTime, "yyyy-MM-dd");
        String endDate = TimeUtil.getDateTimeAsString(endTime, "yyyy-MM-dd");
        List<String> timeList = TimeUtil.getBetweenDays(startDate, endDate);
        if (timeList == null) {
            logger.info("统计日新增的时间范围有误");
            return;
        }

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        List<NewlyAddedDayReportDO> resultList = timeList.stream().map(r -> {
            LocalDateTime key = LocalDateTime.parse(r + " 00:00:00", formatter);
            StatisticsNewlyAddedBO addedBO;

            NewlyAddedDayReportDO reportDO = new NewlyAddedDayReportDO();
            reportDO.setDateTime(key);

            addedBO = Optional.ofNullable(memberNewlyAddedBOS).flatMap(map -> map.stream().filter(o -> o.getDateTime().equals(key)).findFirst()).orElse(null);
            reportDO.setMemberCount(addedBO != null ? addedBO.getCount() : 0);
            addedBO = Optional.ofNullable(shopNewlyAddedBOS).flatMap(map -> map.stream().filter(o -> o.getDateTime().equals(key)).findFirst()).orElse(null);
            reportDO.setShopCount(addedBO != null ? addedBO.getCount() : 0);
            addedBO = Optional.ofNullable(commodityNewlyAddedBOS).flatMap(map -> map.stream().filter(o -> o.getDateTime().equals(key)).findFirst()).orElse(null);
            reportDO.setCommodityCount(addedBO != null ? addedBO.getCount() : 0);
            addedBO = Optional.ofNullable(brandNewlyAddedBOS).flatMap(map -> map.stream().filter(o -> o.getDateTime().equals(key)).findFirst()).orElse(null);
            reportDO.setBrandCount(addedBO != null ? addedBO.getCount() : 0);

            StatisticsOrderNewlyAddedBO orderAddedBO = Optional.ofNullable(orderNewlyAddedBOS).flatMap(map -> map.stream().filter(o -> o.getDateTime().equals(key)).findFirst()).orElse(null);
            reportDO.setOrderAmount(orderAddedBO != null ? orderAddedBO.getAmount() : 0);

            return reportDO;
        }).filter(o -> o.getMemberCount() > 0 || o.getOrderAmount() > 0 || o.getShopCount() > 0 || o.getCommodityCount() > 0 || o.getBrandCount() > 0)    // 剔除都为0的数据
                .collect(Collectors.toList());

        // 新增前先删除数据
        reportRepository.deleteByDateTimeBetween(startTime, endTime);

        // 新增统计数据
        reportRepository.saveAll(resultList);
    }

    /**
     * 查询日新增报表
     * @author 伍将
     * @date 2020/11/12
     * @param user:
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.report.model.vo.response.NewlyAddedDayReportVO>
     **/
    @Override
    public Wrapper<NewlyAddedDayReportVO> getNewlyAddedDayReport(UserLoginCacheDTO user) {

        NewlyAddedDayReportVO result = new NewlyAddedDayReportVO();

        // 查询昨天与当天数据
        LocalDateTime startTime = TimeUtil.parseStringToDateTime(DateUtil.offsetDay(DateUtil.date(), -1).toString("yyyy-MM-dd 00:00:00"), "yyyy-MM-dd HH:mm:ss");
        LocalDateTime endTime = TimeUtil.parseStringToDateTime(DateUtil.date().toString("yyyy-MM-dd 00:00:00"), "yyyy-MM-dd HH:mm:ss");
        List<NewlyAddedDayReportDO> reportDOS = reportRepository.getAllByDateTimeBetween(startTime, endTime);
        if (reportDOS != null && reportDOS.size() > 0) {
            NewlyAddedDayReportDO todayDo = reportDOS.stream().filter(o -> o.getDateTime().equals(endTime)).findFirst().orElse(null);
            NewlyAddedDayReportDO yesterdayDo = reportDOS.stream().filter(o -> o.getDateTime().equals(startTime)).findFirst().orElse(null);

            Long todayMemberCount = 0L;
            Double todayOrderAmount = 0D;
            Long todayCommodityCount = 0L;
            Long todayShopCount = 0L;
            Double yesterdayMemberCount = 0D;
            Double yesterdayOrderAmount = 0D;
            Double yesterdayCommodityCount = 0D;
            Double yesterdayShopCount = 0D;

            if (todayDo != null) {
                todayMemberCount = todayDo.getMemberCount();
                todayOrderAmount = todayDo.getOrderAmount();
                todayCommodityCount = todayDo.getCommodityCount();
                todayShopCount = todayDo.getShopCount();
            }
            if (yesterdayDo != null) {
                yesterdayMemberCount = yesterdayDo.getMemberCount() * 1.0;
                yesterdayOrderAmount = yesterdayDo.getOrderAmount() * 1.0;
                yesterdayCommodityCount = yesterdayDo.getCommodityCount() * 1.0;
                yesterdayShopCount = yesterdayDo.getShopCount() * 1.0;
            }

            // 赋值今日数据
            result.setMemberCount(todayMemberCount);
            result.setOrderAmount(todayOrderAmount);
            result.setCommodityCount(todayCommodityCount);
            result.setShopCount(todayShopCount);

            // 计算会员增长率
            Double memberGrowthRate;
            if (yesterdayMemberCount == 0) {
                memberGrowthRate = todayMemberCount != 0 ? 100D : 0;
            } else {
                memberGrowthRate = (todayMemberCount - yesterdayMemberCount) / yesterdayMemberCount * 100;
            }

            // 计算订单增长率
            Double orderGrowthRate;
            if (yesterdayOrderAmount == 0) {
                orderGrowthRate = todayOrderAmount != 0 ? 100D : 0;
            } else {
                orderGrowthRate = (todayOrderAmount - yesterdayOrderAmount) / yesterdayOrderAmount * 100;
            }

            // 计算商品增长率
            Double commodityGrowthRate;
            if (yesterdayCommodityCount == 0) {
                commodityGrowthRate = todayCommodityCount != 0 ? 100D : 0;
            } else {
                commodityGrowthRate = (todayCommodityCount - yesterdayCommodityCount) / yesterdayCommodityCount * 100;
            }

            // 计算店铺增长率
            Double shopGrowthRate;
            if (yesterdayShopCount == 0) {
                shopGrowthRate = todayShopCount != 0 ? 100D : 0;
            } else {
                shopGrowthRate = (todayShopCount - yesterdayShopCount) / yesterdayShopCount * 100;
            }

            // 赋值增长率
            DecimalFormat format = new DecimalFormat("#.00");
            result.setMemberGrowthRate(Double.parseDouble(format.format(memberGrowthRate)));
            result.setOrderGrowthRate(Double.parseDouble(format.format(orderGrowthRate)));
            result.setCommodityGrowthRate(Double.parseDouble(format.format(commodityGrowthRate)));
            result.setShopGrowthRate(Double.parseDouble(format.format(shopGrowthRate)));
        }

        return Wrapper.success(result);
    }

    /**
     * 更新每日新增
     * @param noticeVO 操作数据
     */
    @Override
    public void update(OperateNoticeVO noticeVO) {
        LocalDateTime startTime = TimeUtil.parseStringToDateTime(DateUtil.date().toString("yyyy-MM-dd 00:00:00"), "yyyy-MM-dd HH:mm:ss");
        NewlyAddedDayReportDO reportDO = reportRepository.getAllByDateTimeBetween(startTime, startTime).stream().findFirst().orElse(null);
        if (reportDO == null) {
            reportDO = new NewlyAddedDayReportDO();
            reportDO.setDateTime(startTime);
        }

        OperateDataSourceEnum sourceEnum = OperateDataSourceEnum.getEnum(noticeVO.getDataSource());
        switch (sourceEnum) {
            case SHOP:
                // 计算变更新增店铺数
                Long shopNum = 0L;
                if (ShopOperateTypeEnum.ADD.getCode().equals(noticeVO.getIncreaseOperateType())) {
                    shopNum = noticeVO.getIncreaseCount();
                }
                if (ShopOperateTypeEnum.ADD.getCode().equals(noticeVO.getReduceOperateType())) {
                    shopNum -= noticeVO.getReduceCount();
                }
                if (shopNum > 0) {
                    reportDO.setShopCount(reportDO.getShopCount() + shopNum);
                    reportRepository.save(reportDO);
                }
                break;
            case PLATFORM_MEMBER_VERIFY:
                // 待确认审核结果减少时，代表审核通过，会员增加
                if (MemberOperateTypeEnum.TO_BE_COMMIT_VALIFY.getCode().equals(noticeVO.getReduceOperateType())
                        && null != noticeVO.getReduceCount()) {
                    reportDO.setMemberCount(reportDO.getMemberCount() + noticeVO.getReduceCount());
                    reportRepository.save(reportDO);
                }
                break;
            case COMMODITY:
                // 计算变更新增商品和品牌数
                Long commodityNum = 0L;
                Long brandNum = 0L;
                if (CommodityOperateTypeEnum.TO_BE_PRODUCT_CHECK_COMMIT.getCode().equals(noticeVO.getIncreaseOperateType())) {
                    commodityNum = noticeVO.getIncreaseCount();
                } else if (CommodityOperateTypeEnum.TO_BE_BRAND_CHECK_COMMIT.getCode().equals(noticeVO.getIncreaseOperateType())) {
                    brandNum = noticeVO.getIncreaseCount();
                }
                if (CommodityOperateTypeEnum.TO_BE_PRODUCT_CHECK_COMMIT.getCode().equals(noticeVO.getReduceOperateType())) {
                    commodityNum -= noticeVO.getReduceCount();
                } else if (CommodityOperateTypeEnum.TO_BE_BRAND_CHECK_COMMIT.getCode().equals(noticeVO.getReduceOperateType())) {
                    brandNum -= noticeVO.getReduceCount();
                }
                if (commodityNum > 0 || brandNum > 0) {
                    reportDO.setCommodityCount(reportDO.getCommodityCount() + commodityNum);
                    reportDO.setBrandCount(reportDO.getBrandCount() + brandNum);
                    reportRepository.save(reportDO);
                }
                break;
        }
    }

    /**
     * 新增每日订单
     * @author 伍将
     * @date 2020/12/8
     * @param addOrderVO :
     **/
    @Override
    public void addOrder(AddOrderVO addOrderVO) {

        // 如果订单金额大于0，则新增订单，订单数增加1；反之为取消订单或审核不通过，订单数-1；增减对应的时间仅为当前时间，补追溯原始来源时间
        LocalDateTime startTime = TimeUtil.parseStringToDateTime(DateUtil.date().toString("yyyy-MM-dd 00:00:00"), "yyyy-MM-dd HH:mm:ss");
        NewlyAddedDayReportDO reportDO = reportRepository.getAllByDateTimeBetween(startTime, startTime).stream().findFirst().orElse(null);
        if (reportDO == null) {
            reportDO = new NewlyAddedDayReportDO();
            reportDO.setDateTime(startTime);
        }
        reportDO.setOrderAmount(reportDO.getOrderAmount() + addOrderVO.getAmount());
        reportRepository.saveAndFlush(reportDO);

    }

    /**
     * 批量新增每日订单
     * @author 伍将
     * @date 2021/2/4
     * @param addOrderVO :请求参数
     **/
    @Override
    public void addOrderList(List<AddOrderVO> addOrderVO) {

        if (null != addOrderVO && addOrderVO.size() > 0) {
            Double amount = addOrderVO.stream().mapToDouble(AddOrderVO::getAmount).sum();
            LocalDateTime startTime = TimeUtil.parseStringToDateTime(DateUtil.date().toString("yyyy-MM-dd 00:00:00"), "yyyy-MM-dd HH:mm:ss");
            NewlyAddedDayReportDO reportDO = reportRepository.getAllByDateTimeBetween(startTime, startTime).stream().findFirst().orElse(null);
            if (reportDO == null) {
                reportDO = new NewlyAddedDayReportDO();
                reportDO.setDateTime(startTime);
            }
            reportDO.setOrderAmount(reportDO.getOrderAmount() + amount);
            reportRepository.saveAndFlush(reportDO);
        }

    }
}
